#pragma once 
#include<iostream>
#include<cstring>
#include<string>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<sys/wait.h>
#include<pthread.h>
#include<fcntl.h>

using namespace std;

const int default_sockfd=-1;
const uint16_t default_port=8080;
const string default_ip="0.0.0.0";
const int back_log=5;

enum
{
    SocketError=2,BindError,ListenError
};

// class ThreadData
// {
// public:
//     ThreadData(int sockfd,const string& ip,uint16_t port,TcpServer* ts):_sockfd(sockfd),_ip(ip),_port(port),_ts(ts)
//     {}
// public:
//     int _sockfd;
//     string _ip;
//     uint16_t _port;
//     TcpServer* _ts;
// };

// void* Routine(void* args)
// {
//     pthread_detach(pthread_self());
//     ThreadData* td=static_cast<ThreadData*>(args);

//     td->_ts->Service(td->_sockfd,td->_ip,td->_port);
// }

class TcpServer
{
public:
    TcpServer(const uint16_t& port=default_port,const string ip=default_ip):_port(port),_ip(ip)
    {
        
    }
    void InitServer()
    {
        //创建套接字
        _listensockfd=socket(AF_INET,SOCK_STREAM,0);
        if(_listensockfd<0)
        {
            cout<<"create _listensockfd fail,error:"<<errno<<"strerror:"<<strerror<<endl;
            exit(SocketError);
        }
        cout<<"create _listensockfd successfully! _listensockfd is: "<<_listensockfd<<endl;

        int opt=1;
        setsockopt(_listensockfd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));

        int fl=fcntl(_listensockfd,F_GETFL);
        if(fl<0)exit(1);
        fcntl(_listensockfd,fl|O_NONBLOCK);

        //初始化套接字信息
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        inet_aton(_ip.c_str(),&local.sin_addr);

        //bind套接字到内核
        int ret=bind(_listensockfd,(struct sockaddr*)&local,sizeof(local));
        if(ret<0)
        {
            cout<<"bind _listensockfd fail,error:"<<errno<<"strerror:"<<strerror<<endl;
            exit(BindError);
        }
        cout<<"bind _listensockfd successfully! success:"<<errno<<"strsuccess:"<<strerror<<endl;

        //Tcp是面向连接的，服务器一般是比较被动的
        if(listen(_listensockfd,back_log)<0)
        {
            cout<<"listen error,errno:"<<errno<<"strerror:"<<strerror(errno)<<endl;
            exit(ListenError);
        }
        cout<<"listen _listensockfd successfully! success:"<<errno<<"strsuccess:"<<strerror<<endl;
    }
    void Start()
    {
        cout<<"tcpServer is running..."<<endl;
        for( ; ; )
        {
            //1.获取新链接的属性数据
            struct sockaddr_in client;
            socklen_t len=sizeof(client);

            int sockfd=accept(_listensockfd,(struct sockaddr*)&client,&len);
            if(errno==EWOULDBLOCK)
            {
                cout<<"EWOULDBLOCK..."<<endl;
                break;
            }
            if(sockfd<0)
            {
                cout<<"accept error,errno:"<<errno<<"strerror:"<<strerror(errno)<<endl;
                continue;
            }
            uint16_t clientport=ntohs(client.sin_port);
            char clientip[32];

            inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));   
            //2.根据新连接来进行通信
            cout<<"get a new link...sockfd:"<<sockfd<<"client ip:"<<clientip<<"client port:"<<clientport<<endl;
            //version-1 单进程版
            Service(sockfd,clientip,clientport);
            close(sockfd);

            //version-2 多进程版
            // pid_t id=fork();
            // if(id==0)
            // {
            //     close(_listensockfd);
            //     //子进程
            //     if(fork()>0)exit(0);
            //     Service(sockfd,clientip,clientport);
            //     close(sockfd);
            //     exit(0);
            // }
            // close(sockfd);
            // //父进程
            // pid_t rid=waitpid(id,nullptr,0);

            //version-3 多线程版
            // ThreadData* td=new ThreadData(sockfd,clientip,clientport,this);
            // pthread_t tid;
            // pthread_create(&tid,nullptr,Routine,td);
        }
    }
    void Service(int sockfd,const string& clientip,const uint16_t& clientport)
    {
        //测试代码
        char buffer[4096]={0};
        while(true)
        {
            ssize_t n=read(sockfd,buffer,sizeof(buffer));
            if(n>0)
            {
                buffer[n]='\0';
                cout<<"client say# "<<buffer<<endl;
                string echo_result ="tcpserver echo# ";
                echo_result+=buffer;

                write(sockfd,echo_result.c_str(),echo_result.size());
            }
            else if(n==0)
            {
                cout<<clientip<<","<<clientport<<"quit! "<<sockfd<<"server close too"<<endl;
                break;
            }
            else 
            {
                cout<<"read error,sockfd:"<<sockfd<<"client ip:"<<clientip<<"client port:"<<clientport<<endl;
                break;
            }
        }
    }
    ~TcpServer()
    {
        close(_listensockfd);
    }
private:
    int _listensockfd;
    uint16_t _port;
    string _ip;
};